package me.chyxion.spring.ext.view;

import java.util.Locale;
import java.util.Map;
import javax.annotation.PostConstruct;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import me.chyxion.spring.ext.DataModel;
import me.chyxion.spring.ext.DataModelAssembler;
import me.chyxion.spring.ext.utils.ResponseTool;
import org.springframework.core.Ordered;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.ViewResolver;
import com.alibaba.fastjson.support.spring.FastJsonJsonView;
import org.springframework.beans.factory.annotation.Autowired;

/**
 * @version 0.0.3
 * @since 0.0.1
 * @author Shaun Chyxion <br />
 * chyxion@163.com <br />
 * Jul 16, 2014 9:45:36 PM
 */
public class DefaultViewResolver implements ViewResolver, Ordered {
	private static final Logger log = 
		LoggerFactory.getLogger(DefaultViewResolver.class);

	@Autowired(required = false)
	private DataModelAssembler modelAssembler;

    /**
     * view resolver order
     */
    private int order;

    @Autowired
    private ResponseTool responseTool;

    /*
     * (non-Javadoc)
     * @see org.springframework.web.servlet.ViewResolver#resolveViewName(java.lang.String, java.util.Locale)
     */
    @Override
    public View resolveViewName(String rawViewName, Locale locale) throws Exception {
    	log.debug("Base View Resolver Resolve View Name [{}].", rawViewName);
        // parse view name
        View view = null;
        if (rawViewName.startsWith(ResponseTool.PREFIX_DATA)) {
        	String viewName = rawViewName.substring(ResponseTool.PREFIX_DATA.length());
        	log.debug("Resolve View Name [{}] As JSON Data.", viewName);
        	view = new JSONView(viewName);
        }

        if (view == null) {
        	log.debug("No View Type Found, Render As JSON View [{}].", rawViewName);
        	view = new JSONView(rawViewName);
        }
        return view;
    }

    @PostConstruct
    public void postInit() {
    	log.debug("Post Defaul View Resolver Init.");
    	if (modelAssembler != null) {
    		log.debug("Custom Model Renderer Found.");
    		JSONView.MODEL_ASSEMBLER = modelAssembler;
    	}
    }

    /*
     * (non-Javadoc)
     * @see org.springframework.core.Ordered#getOrder()
     */
    @Override
    public int getOrder() {
        return order;
    }

    /**
     * @param order the order to set
     */
    public void setOrder(int order) {
        this.order = order;
    }
    
	public static class JSONView extends FastJsonJsonView {
		private static DataModelAssembler MODEL_ASSEMBLER = null;
		private DataModel dataModel;

		private static final Logger log = 
				LoggerFactory.getLogger(JSONView.class);
		
		public JSONView(DataModel dataMoel) {
			this.dataModel = dataMoel;
		}

		public JSONView(String viewName) {
			setBeanName(viewName);
		}

		@Override
		protected Object filterModel(Map<String, Object> model) {
			if (dataModel == null) {
				dataModel = buildDataModel(model);
			}
			return MODEL_ASSEMBLER != null ? 
				MODEL_ASSEMBLER.assemble(dataModel) : dataModel.formattedData();
		}

		@SuppressWarnings("unchecked")
		private DataModel buildDataModel(Map<String, Object> model) {
			log.debug("Build Data Model From Map Model.");
			Object objData = null;
			DataModel dataModel = new DataModel(null);
			// raw data
			if (Boolean.TRUE.equals(model.remove(ResponseTool.MARK_RAW))) {
				log.debug("Render Raw Data Model.");
				objData = model;
				dataModel.setRaw(true);
			}
			else if (Boolean.TRUE.equals(model.get(ResponseTool.MARK_DATA))) {
				log.debug("Render Data.");
				objData = model.get("data");
				// keep raw map data
				dataModel.setRaw(objData instanceof Map &&
					Boolean.TRUE.equals(
						((Map<String, ?>) objData)
							.remove(ResponseTool.MARK_RAW)));
			}
			else {
				// default bean name
				objData = getBeanName();
				log.debug("Could Not Find Any Resource, Render As Data [{}].", objData);
			}
			dataModel.setData(objData);
			return dataModel;
		}
	}
}
